package com.softwarecraftsmen.orogeny.filing;

import com.softwarecraftsmen.orogeny.filing.findFileFilters.FindFilesFilter;
import com.softwarecraftsmen.orogeny.filing.findSubdirectoriesFilters.FindSubdirectoriesFilter;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.StringWriter;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * This file is Copyright © 2009 Vubble Limited. All Rights Reserved.
 */
public class FilesFilteredAbsolutePaths implements AbsolutePaths
{
	@NotNull
	public static FilesFilteredAbsolutePaths filesFilteredAbsolutePaths(final @NotNull AbsolutePaths absolutePaths, final @NotNull FindFilesFilter findFilesFilter)
	{
		return new FilesFilteredAbsolutePaths(absolutePaths, findFilesFilter);
	}

	private final AbsolutePaths absolutePaths;
	private final FindFilesFilter findFilesFilter;

	public FilesFilteredAbsolutePaths(final @NotNull AbsolutePaths absolutePaths, final @NotNull FindFilesFilter findFilesFilter)
	{
		this.absolutePaths = absolutePaths;
		this.findFilesFilter = findFilesFilter;
	}

	@NotNull
	public AbsolutePaths and(final @NotNull AbsolutePath absolutePath)
	{
		return new FilesFilteredAbsolutePaths(this.absolutePaths.and(absolutePath), findFilesFilter);
	}

	@NotNull
	public AbsolutePaths and(final @NotNull AbsolutePaths absolutePaths)
	{
		return new FilesFilteredAbsolutePaths(this.absolutePaths.and(absolutePaths), findFilesFilter);
	}

	@NotNull
	public String toFileSystemSpecificPath()
	{
		final StringWriter writer = new StringWriter();
		boolean afterFirst = false;
		final Set<AbsolutePath> filesAndFolders = new LinkedHashSet<AbsolutePath>()
		{{
			addAll(files());
			addAll(directories());
		}};
		for (AbsolutePath fileOrFolder : filesAndFolders)
		{
			if (afterFirst)
			{
				writer.write(fileOrFolder.toFileSystemSpecificPathPrefixedByPathSeparator());
			}
			else
			{
				writer.write(fileOrFolder.toFileSystemSpecificPath());
			}
			afterFirst = true;
		}
		return writer.toString();
	}

	public boolean exists()
	{
		for (AbsoluteFile absoluteFile : files())
		{
			if (!absoluteFile.exists())
			{
				return false;
			}
		}
		for (AbsoluteDirectory absoluteDirectory : directories())
		{
			if (!absoluteDirectory.exists())
			{
				return false;
			}
		}
		return true;
	}

	public boolean isEmpty()
	{
		return toFiles().isEmpty();
	}

	@NotNull
	public Set<File> toFiles()
	{
		final LinkedHashSet<File> files = new LinkedHashSet<>();
		for (AbsoluteFile absoluteFile : files())
		{
			files.add(absoluteFile.toFile());
		}
		for (AbsoluteDirectory absoluteDirectory : directories())
		{
			files.add(absoluteDirectory.toFile());
		}
		return files;
	}

	@NotNull
	public Set<AbsoluteFile> findFiles(final @NotNull FindFilesFilter findFilesFilter)
	{
		return new FilesFilteredAbsolutePaths(absolutePaths, this.findFilesFilter.and(findFilesFilter)).files();
	}

	@NotNull
	public Set<AbsoluteDirectory> findSubdirectories(final @NotNull FindSubdirectoriesFilter findSubdirectoriesFilter)
	{
		return absolutePaths.findSubdirectories(findSubdirectoriesFilter);
	}

	@NotNull
	public Set<AbsoluteFile> files()
	{
		return absolutePaths.findFiles(findFilesFilter);
	}

	@NotNull
	public Set<AbsoluteDirectory> directories()
	{
		return absolutePaths.directories();
	}
}
